package com.yanqu.road.player;

import com.yanqu.road.connect.AgentServerLinkControl;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.task.DelayOfflineTask;
import com.yanqu.road.utils.MD5Security;
import com.yanqu.road.utils.UUIDHelper;
import io.netty.channel.Channel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;


public class PlayerControl {

	private static Logger logger = LogManager.getLogger(PlayerControl.class.getName());

	private static Map<Long, Player> onlinePlayerMap;
	private static Map<Long, Channel> cacheChannelMap;
	private static Timer delayTimer;

	private static Map<String, Long> tokenUserIdMap;

	public static Player getOnlinePlayer(long playerId) {
		return onlinePlayerMap.get(playerId);
	}

	public static Map<Long, Player> getOnlinePlayerMap() {
		return onlinePlayerMap;
	}

	public static boolean init() {
		onlinePlayerMap = new ConcurrentHashMap<>();
		cacheChannelMap = new ConcurrentHashMap<>();
		delayTimer = new Timer("delayTimer");
		tokenUserIdMap = new ConcurrentHashMap<>();

//		RedisServerOnlineCount.setOnlineCount(AgentServer.getInstance().getServerId(),0);
		return true;
	}

	public static void addPlayerOnline(long playerId, Channel channel) {
		addToOnlinePlayerMap(playerId, channel);
		YanQuMessage yanQuMessage = new YanQuMessage(Protocol.S_PLAYER_LOGIN);
		yanQuMessage.setPlayerId(playerId);
		AgentServerLinkControl.routeGame(yanQuMessage);
	}

	public static void addToOnlinePlayerMap(long playerId, Channel channel){
		synchronized (onlinePlayerMap) {
			Player player = onlinePlayerMap.get(playerId);
			if (null == player) {
				player = new Player(playerId, channel);
				onlinePlayerMap.put(playerId, player);
			} else {
				player.setChannel(channel);
			}
//			RedisServerOnlineCount.setOnlineCount(AgentServer.getInstance().getServerId(), onlinePlayerMap.size());
		}
	}

	public static void delayRemovePlayerOnline(long playerId, Channel channel) {
		delayTimer.schedule(new DelayOfflineTask(playerId, channel), 500);
	}

	public static boolean kickOutPlayer(long playerId) {
		Player player = getOnlinePlayer(playerId);
		if (null != player) {
			removePlayerOnline(playerId, player.getChannel(),true);
			removeLoginToken(playerId); //踢下线一定要移除登录口令
			return true;
		}else{
			removePlayerOnline(playerId, null,true);
		}
		return false;
	}

	public static void removePlayerOnline(long playerId, Channel channel, boolean isKick) {
		try {
			playerOffline(playerId, channel,isKick);
			Channel tempChannel = removeChannelCache(playerId);
			if (null != tempChannel) {
				tempChannel.close().sync();
			}
		} catch (InterruptedException e) {
			logger.error("removePlayerOnline error:", e);
		}
	}

	private static void playerOffline(long playerId, Channel channel, boolean isKick) {
		boolean isRemoveOnline = true;
		Player player = getOnlinePlayer(playerId);
		if (null == player || channel != player.getChannel()) {
			logger.warn("player already remove, playerId : {}" , playerId);
			isRemoveOnline = false;
		}

		if(isRemoveOnline){
			onlinePlayerMap.remove(playerId);
//			RedisServerOnlineCount.setOnlineCount(AgentServer.getInstance().getServerId(), onlinePlayerMap.size());

			player.closeChannel();

//			removeLoginToken(playerId);//短线重连客户端没有重新请求WebLogin获得新的口令,所以不移出内存了
		}

		gameServerOffline(playerId,isKick);
	}

	private static void gameServerOffline(long playerId, boolean isKick){
		int protocol = Protocol.S_PLAYER_LOGOUT;
		if(isKick){
			protocol = Protocol.S_KICK_OUT_PLAYER;
		}
		YanQuMessage yanQuMessage = new YanQuMessage(protocol);
		yanQuMessage.setPlayerId(playerId);
		AgentServerLinkControl.routeGame(yanQuMessage);
	}

	public static void stop() {
		try {
			for (Channel channel : cacheChannelMap.values()) {
				channel.close().sync();
			}

			for (Entry<Long, Player> entry : onlinePlayerMap.entrySet()) {
				Player temp = entry.getValue();
				temp.closeChannel();
			}
		} catch (Exception e) {
			logger.error("关闭channel异常.", e);
		}
	}

	public static void addChannelCache(long playerId, Channel channel) {
		cacheChannelMap.put(playerId, channel);
	}

	public static Channel removeChannelCache(long playerId) {
		return cacheChannelMap.remove(playerId);
	}

	public static String matchOneLoginToken(long userId) {
		String oldToken = null;
		for (Entry<String, Long> entry : tokenUserIdMap.entrySet()) {
			if (entry.getValue() == userId) {
				oldToken = entry.getKey();
				break;
			}
		}
		if (oldToken != null) {
			tokenUserIdMap.remove(oldToken);
		}

		String newToken = UUIDHelper.randomUUID(String.valueOf(userId));
		try {
			newToken = MD5Security.md5(newToken).toLowerCase();
		} catch (Exception e) {
			logger.error("md5 error.", e);
		}

		tokenUserIdMap.put(newToken, userId);
		return newToken;
	}

	public static Long getUserIdByToken(String token) {
		return tokenUserIdMap.get(token);
	}

	public static void removeLoginToken(long userId) {
		List<String> removeList = new ArrayList<>();
		for (Entry<String, Long> entry : tokenUserIdMap.entrySet()) {
			if (entry.getValue() == userId) {
				String loginToken = entry.getKey();
				removeList.add(loginToken);
			}
		}

		for(String token : removeList){
			tokenUserIdMap.remove(token);
		}
	}
}
